Spring Security 프로젝트 설정 5 - Security CORS 설정
✒️ 2025-05-28 14:23 내용 수정
-
참고 자료 : Spring Security CORS 공식 문서, Spring Security 및 Access Token, Refresh Token, 개발자 유미의 Spring Security CORS 설정
-
SpringSecurity 프로젝트 설정 목록
- Spring Security 기본 사용자 추가 및 테스트
- Spring Security 프로젝트 설정 1 - DB연결과 JPA 설정
- Spring Security 프로젝트 설정 2 - JwtService와 Filter 설정
- Spring Security 프로젝트 설정 3 - Security Config
- Spring Security 프로젝트 설정 4 - Authentication Service와 Controller
- Spring Security 프로젝트 설정 5 - Security CORS 설정
- Spring Security 프로젝트 설정 6 - JWT Refresh Token 생성 및 저장
- Spring Security 프로젝트 설정 7 - JWT Refresh Token 재발급
- Spring Security 프로젝트 설정 8 - JWT 클라이언트 저장
- Spring Security 프로젝트 설정 9 - JWT 로그아웃
- Spring Security 프로젝트 설정 10 - 권한 설정
흐름

Spring MVC CORS 설정
- Spring boot 서버와 클라이언트를 같은 출처(ex. 같은 개발 컴퓨터)에서 가동할 때 보안 상의 이유로 브라우저는 교차 출처 HTTP 요청을 제하며, CORS 체제는 브라우저와 서버 간의 안전한 교차 출처 요청 및 데이터 전송을 지원한다.
- 서버와 클라이언트 간의 데이터 교환을 허용하기 위해 Spring Boot와 React 연동 설정에서
WebMvcConfigurer를 사용하여 CORS 설정을 진행했었다.- Spring boot와 React 연계#통신을 위한 설정(CORS 포함) 참고.
WebMvcConfigurer은 Spring MVC에 대한 설정을 커스터마이징할 수 있는 인터페이스로, URL 매핑과 CORS 설정 등을 적용할 수 있다.- Spring Security에서
.cors(withDefault())를 적용하지 않는다면 이 설정은 Spring MVC에만 적용된다.
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
@RequiredArgsConstructor
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowCredentials(true)
.allowedOrigins("http://localhost:3000")
.allowedMethods("OPTIONS", "GET", "POST", "PATCH", "DELETE");
}
}
Spring Security CORS 설정 (CorsConfigurationSource)
- CORS는 Spring Security 이전에 진행해야 하는데, 사전에 들어온 요청은 cookie를 포함하지 않아 Spring Security에서 사용자의 인증 상태를 확인하고 해당 요청을 거절하기 때문이다.
- CORS를 설정하는 방법은
CorsFilter를 사용하는 방법이 있으며,CorsConfigurationSource를 제공하여 Spring Security와CorsFilter를 통합할 수 있다. CorsConfigurationSource는 Spring Security에서 CORS 설정을 관리할 수 있도록 도와주는 인터페이스로, 각 요청에 대한 CORS 구성을 동적으로 구성할 수 있다.- Spring Security는
UrlBasedCorsConfigurationSource인스턴스가 존재할 때만 자동으로 CORS를 설정한다. - 여러 개의
CorsConfigurationSourceBean을 사용할 경우 Spring Security는 어느 Bean을 사용할지 결정하지 못해 자동으로 CORS 구성을 진행하지 못한다. 따라서 각SecurityFilterChain에 다른CorsConfigurationSourceBean을 사용한다면.cors()에 직접 넘겨줘야 한다.
- Spring Security는
- 아래는 공식 문서의 예시다.
@Configuration
@EnableWebSecurity
public class WebSecurityConfig {
@Bean
@Order(0)
public SecurityFilterChain apiFilterChain(HttpSecurity http) throws Exception {
http
.securityMatcher("/api/**")
.cors((cors) -> cors
.configurationSource(apiConfigurationSource())
)
...
return http.build();
}
@Bean
@Order(1)
public SecurityFilterChain myOtherFilterChain(HttpSecurity http) throws Exception {
http
.cors((cors) -> cors
.configurationSource(myWebsiteConfigurationSource())
)
...
return http.build();
}
// 첫 번째 필터에 사용되는 UrlBasedCorsConfigurationSource
UrlBasedCorsConfigurationSource apiConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("https://api.example.com"));
configuration.setAllowedMethods(Arrays.asList("GET","POST"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
// 두 번째 필터에 사용되는 UrlBasedCorsConfigurationSource
UrlBasedCorsConfigurationSource myWebsiteConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("https://example.com"));
configuration.setAllowedMethods(Arrays.asList("GET","POST"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}
SecurityConfig 수정
- Spring Security 설정을 저장한
SecurityConfig클래스에 CORS 설정을 추가한다.
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import java.util.Collections;
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig {
private final JwtAuthenticationFilter jwtAuthFilter;
private final AuthenticationProvider authenticationProvider;
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception{
http
// session stateless로 인해 꺼 둠
.csrf((auth)->auth.disable())
.authorizeRequests()
.requestMatchers("/api/v1/auth/**") // 나열된 요청들은
.permitAll() // 모두 허용
.anyRequest() // 그 외의 모든 요청은
.authenticated() // 인증 필요
.and()
.sessionManagement((session)->
session // session state는 저장되면 안되므로 stateless로 설정
.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authenticationProvider(authenticationProvider)
.addFilterBefore(jwtAuthFilter,
UsernamePasswordAuthenticationFilter.class); // jwt 필터 가동
// cors 설정
http.
cors((corsConfigurer)->
corsConfigurer.configurationSource(corsConfigurationSource()));
return http.build();
}
// CORS 설정
@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration corsConfiguration = new CorsConfiguration();
// React client Origin을 허용
corsConfiguration.setAllowedOrigins(Collections.singletonList("http://localhost:3000"));
// React client로부터 오는 모든 메소드 허용
corsConfiguration.setAllowedMethods(
Collections.singletonList(
"GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"
)
);
// React client로부터 오는 credential(cookie) 허용
corsConfiguration.setAllowCredentials(true);
// React client로부터 오는 모든 헤더를 허용
corsConfiguration.setAllowedHeaders(Collections.singletonList("*"));
corsConfiguration.setMaxAge(3600L);
// 클라이언트에 노출될 Authorization 헤더 설정
corsConfiguration.setExposedHeaders(Collections.singletonList("Authorization"));
// cors 설정을 URL에 매핑
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
// 모든 경로에 대해 CORS 설정 적용
source.registerCorsConfiguration("/**", corsConfiguration);
return source;
}
}
MvcConfig 추가
- 참고 자료 : WebMvcConfigurer 인터페이스와 설정
config패키지에WebMvcConfigurer인터페이스를 구현하는CorsMvcConfig클래스를 추가한다.addCorsMappings()를 오버라이드해서 CORS 구성을 직접 지정하고, 클래스에 설정된 내용은 모든 Spring MVC endpoint에 대해 CORS 정책을 적용한다.@EnableWebMvc는 MVC 설정을 추가하는 Annotation으로, 참고 자료에 따르면 예시 중 ViewResolver 설정을 추가하기 위해WebMvcConfigurer타입의 bean 객체의configureViewResolvers()메소드를 호출한다고 한다.
package com.ase.serverckecklist.security.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration // bean 등록
@EnableWebMvc
public class CorsMvcConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**") // mapping 설정
.maxAge(500) // 기간
.allowedOrigins("http://localhost:3000") // origin
// 허용 메소드
.allowedMethods("GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS");
}
}
- 위에서
SecurityConfig만 설정하고 해당 클래스를 작성하지 않았더니 아래의 에러가 발생했었다.
Access to XMLHttpRequest at 'http://localhost:9000/api/servers/' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.